﻿using System;
using System.Linq;
using System.Text;
using System.Threading;

namespace FixedHeaderSample.Client
{
    public class SocketSession
    {
        #region 线程

        private Thread _threadWorker;
        private readonly AutoResetEvent _stopThreadEvent;

        #endregion

        private int _port;

        private readonly SocketClientHelper _socketClientHelper;

        public SocketSession()
        {
            _socketClientHelper = new SocketClientHelper();
            _socketClientHelper.Connected += OnSocketConnected;
            _socketClientHelper.Closed += OnSocketClosed;
            _socketClientHelper.Error += OnSocketError;
            _socketClientHelper.DataReceived += OnDataReceived;

            _stopThreadEvent = new AutoResetEvent(false);
        }

        public void Start(int port)
        {
            _port = port;
            Console.WriteLine($@"{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff} 正在连接Socket服务器");
            _socketClientHelper.Start(@"127.0.0.1", _port);

            _stopThreadEvent.Reset();
            _threadWorker = new Thread(DoWork)
            {
                IsBackground = true
            };
            _threadWorker.Start();
        }

        public void Stop()
        {
            _socketClientHelper.Stop();

            _stopThreadEvent.Set();
            if (_threadWorker != null)
            {
                _threadWorker.Join();
                _threadWorker = null;
            }
        }

        #region Socket event handlers

        private void OnSocketConnected()
        {
            Console.WriteLine($@"{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff} Socket服务器连接成功");
        }

        private void OnSocketClosed()
        {
            Console.WriteLine($@"{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff} Socket服务器断开，正在重新连接");

            Thread.Sleep(1);
            _socketClientHelper.Start(@"127.0.0.1", _port);
        }

        private void OnSocketError(Exception e)
        {
            Console.WriteLine($@"{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff} Socket异常:{e.Message}，重新连接服务器");

            Thread.Sleep(1);
            _socketClientHelper.Start(@"127.0.0.1", _port);
        }

        private void OnDataReceived(byte[] data, int offset, int length)
        {
            var buffer = new byte[length];
            Buffer.BlockCopy(data, offset, buffer, 0, length);
            var message = Encoding.UTF8.GetString(buffer);
            Console.WriteLine($@"{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff} 收到Socket服务器消息:{message}");
        }

        #endregion

        #region GetRandomData

        private static byte[] GetRandomData(Random random)
        {
            var value1 = random.Next(0, 500) / 10f; //0~50℃
            var value2 = random.Next(30, 60); //30~60%
            var temperature = (short) (value1 * 10); //温度
            var humidity = (short) (value2 * 10); //湿度
            Console.WriteLine($@"{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff} temperature: {value1}℃, humidity: {value2}%.");

            var dataBuffer = new byte[4];
            dataBuffer[0] = (byte) (temperature >> 8);
            dataBuffer[1] = (byte) (temperature & 0xFF);
            dataBuffer[2] = (byte) (humidity >> 8);
            dataBuffer[3] = (byte) (humidity & 0xFF);

            var header = new byte[] {0xFF, 0xFE};
            var len = (short) (dataBuffer.Length + 5);
            var lenBuffer = GetBuffer(len);

            var cks = GetSumData(header);
            cks += GetSumData(lenBuffer);
            cks += GetSumData(dataBuffer);

            var buffer = new byte[len];

            //Header
            var offset = 0;
            Buffer.BlockCopy(header, 0, buffer, offset, header.Length);
            //Length
            offset += header.Length;
            Buffer.BlockCopy(lenBuffer, 0, buffer, offset, lenBuffer.Length);
            //Data
            offset += lenBuffer.Length;
            Buffer.BlockCopy(dataBuffer, 0, buffer, offset, dataBuffer.Length);
            //CKS
            offset += dataBuffer.Length;
            buffer[offset] = cks;

            return buffer;
        }

        private static byte[] GetBuffer(short value)
        {
            var buffer = new byte[2];
            buffer[0] = (byte) (value << 8 & 0xFF); //高位
            buffer[1] = (byte) (value & 0x00FF); //低位
            return buffer;
        }

        private static byte GetSumData(byte[] data)
        {
            return data.Aggregate<byte, byte>(0, (current, item) => (byte) (current + item));
        }

        #endregion

        private void DoWork()
        {
            var random = new Random(DateTime.Now.Millisecond);
            while (true)
            {
                var data = GetRandomData(random);
                _socketClientHelper.Send(data);

                //10s发送一次数据
                if (_stopThreadEvent.WaitOne(3000))
                {
                    break;
                }
            }

            Console.WriteLine($@"{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff} DoWork exit.");
        }
    }
}
